home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / ci.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  7KB  |  334 lines

  1. /* ci - check in             Author: Peter S. Housel 12/17/87 */
  2.  
  3. #include <sys/types.h>
  4. #include <string.h>
  5. #include <sys/stat.h>
  6. #include <pwd.h>
  7. #include <signal.h>
  8. #include <stdio.h>
  9.  
  10. #define SUFFIX        ",S"    /* svc indicator */
  11. #define SVCDIR        "SVC"    /* svc postfix indicator */
  12.  
  13. #define LINELEN        256    /* maximum line length */
  14.  
  15. #ifndef PATCH
  16. #define FIX        "fix $1 Fix.$1 > New.$1; mv New.$1 $1\n"
  17. #else
  18. #define FIX        "patch -n -s $1 < Fix.$1; rm -f $1.orig\n"
  19. #endif /* !PATCH */
  20.  
  21. #ifdef MAXPATHLEN
  22. #define PATHLEN MAXPATHLEN
  23. #else
  24. #define PATHLEN 128        /* buffer length for filenames */
  25. #endif
  26.  
  27. int unlocked = 0;        /* leave unlocked after checkin */
  28. int relock = 0;            /* lock next revision after checkin */
  29. char file[PATHLEN];        /* file to be checked in */
  30. char svc[PATHLEN];        /* filename for svc file */
  31. char newsvc[PATHLEN];        /* new copy of SVC file */
  32. char line[LINELEN];        /* temporary line buffer */
  33. char *p;            /* scratch character pointer */
  34.  
  35. FILE *svcfp;            /* svc file */
  36. FILE *origfp, *newfp;        /* "orig" and "new" temp files */
  37. FILE *srcfp;            /* source file */
  38. int rev;            /* new revision number */
  39. int status;            /* wait() buffer */
  40. struct stat stb1, stb2;        /* stat buffers for size compare */
  41. char original[] = "/tmp/cioXXXXXX";    /* previous revision */
  42. char diffout[] = "/tmp/cidXXXXXX";    /* diffs */
  43.  
  44. extern char *mktemp();
  45. extern char *ctime();
  46.  
  47. char *whoami();
  48. void onintr();
  49.  
  50. main(argc, argv)
  51. int argc;
  52. char **argv;
  53. {
  54. #ifdef perprintf
  55.   char errbuf[BUFSIZ];
  56.   setbuf(stderr, errbuf);
  57.   perprintf(stderr);
  58. #endif
  59.  
  60.   while (++argv, --argc) {
  61.     if ('-' == (*argv)[0]) {
  62.         if ('u' == (*argv)[1])
  63.             ++unlocked;
  64.         else if ('l' == (*argv)[1])
  65.             ++relock;
  66.         else {
  67.             fprintf(stderr, "ci: illegal option -%c\n", (*argv)[1]);
  68.             exit(1);
  69.         }
  70.     } else
  71.         break;
  72.   }
  73.  
  74.   if (1 != argc) {
  75.     fprintf(stderr, "ci: bad number of files arguments\n");
  76.     exit(1);
  77.   }
  78.   fname(*argv, file);
  79.   svcname(file, svc);
  80.  
  81.   fprintf(stderr, "%s -> %s\n", file, svc);
  82.  
  83.   signal(SIGHUP, onintr);
  84.   signal(SIGINT, onintr);
  85.   signal(SIGTERM, onintr);
  86.  
  87. #ifndef BSD
  88.   if (NULL == (p = strrchr(file, '/')))
  89.     p = file;
  90.   else
  91.     ++p;
  92.  
  93.   if (strlen(p) > 13) {
  94.     fprintf(stderr, "ci: filename %s is too long\n");
  95.     exit(1);
  96.   }
  97. #endif /* !BSD */
  98.  
  99.   strcpy(newsvc, svc);
  100.   *(strrchr(newsvc, ',')) = ';';    /* temporary file will be "file;S" */
  101.  
  102.   if (NULL == (newfp = fopen(newsvc, "w"))) {
  103.     perror("ci: can't create SVC temporary");
  104.     exit(1);
  105.   }
  106.   (void) mktemp(original);
  107.   (void) mktemp(diffout);
  108.  
  109.   if (NULL != (svcfp = fopen(svc, "r"))) {    /* does svc-file exist? */
  110.     fgets(line, LINELEN, svcfp);
  111.     if (1 != sscanf(line, "# %d", &rev)) {
  112.         fprintf(stderr, "ci: %s: illegal SVC file header\n", svc);
  113.         exit(1);
  114.     }
  115.     ++rev;
  116.  
  117.     if (!lockcheck(svcfp, rev)) {
  118.         fprintf(stderr, "Revision %d not locked\n", rev);
  119.         clean();
  120.         exit(1);
  121.     }
  122.     if (NULL == (origfp = fopen(original, "w"))) {
  123.         fprintf(stderr, "ci: can't create %s", original);
  124.         perror("");
  125.     }
  126.     fgets(line, LINELEN, svcfp);    /* skip "cat <<***MAIN-eof***" line */
  127.  
  128.     while (NULL != fgets(line, LINELEN, svcfp)
  129.            && strcmp(line, "***MAIN-eof***\n")) {
  130.         fputs(line, origfp);
  131.         if (ferror(origfp)) {
  132.             perror("ci: origfile");
  133.             exit(1);
  134.         }
  135.     }
  136.     fclose(origfp);
  137.  
  138.     rundiff();
  139.  
  140.     if (0 != stat(original, &stb1) || 0 != stat(diffout, &stb2)) {
  141.         perror("ci: can't stat original or diffout");
  142.         clean();
  143.         exit(1);
  144.     }
  145.   } else {            /* no - create one */
  146.     rev = 1;
  147.   }
  148.  
  149.   fprintf(newfp, "# %d\n", rev);
  150.   fprintf(newfp, "cat <<***MAIN-eof*** >$1\n");
  151.   if (NULL == (srcfp = fopen(file, "r"))) {
  152.     perror("ci: can't read source file");
  153.     clean();
  154.     exit(1);
  155.   }
  156.   while (NULL != fgets(line, LINELEN, srcfp)) fputs(line, newfp);
  157.   fclose(srcfp);
  158.   fputs("***MAIN-eof***\n", newfp);
  159.  
  160.   if (rev > 1) {
  161.     fprintf(newfp, "if test $2 -ge %d ; then rm -f Fix.$1 ; exit 0 ; fi ; cat <<***%d-eof*** >Fix.$1\n", rev, rev);
  162.     p = (stb1.st_size <= stb2.st_size) ? original : diffout;
  163.     if (NULL == (origfp = fopen(p, "r"))) {
  164.         perror("can't open diff output file");
  165.         clean();
  166.         exit(1);
  167.     }
  168.     while (NULL != fgets(line, LINELEN, origfp)) fputs(line, newfp);
  169.     fclose(origfp);
  170.     fprintf(newfp, "***%d-eof***\n", rev);
  171.     fputs((original == p) ? "mv Fix.$1 $1\n" : FIX, newfp);
  172.     logmsg(newfp);
  173.     while (NULL != fgets(line, LINELEN, svcfp) && strncmp(line, "#***SVCLOCK***", 14))
  174.         fputs(line, newfp);
  175.   } else {
  176.     logmsg(newfp);
  177.     fputs("rm -f Fix.$1\n", newfp);
  178.   }
  179.  
  180.   if (relock) {
  181.     fprintf(stderr, "(relocking into revision %d)\n", rev + 1);
  182.     fprintf(newfp, "#***SVCLOCK*** %s %d\n", whoami(), rev + 1);
  183.   }
  184.   signal(SIGHUP, SIG_IGN);    /* disable during critical section */
  185.   signal(SIGINT, SIG_IGN);
  186.  
  187.   if (ferror(newfp) || fclose(newfp) || ((rev > 1) && unlink(svc))
  188.       || link(newsvc, svc)) {
  189.     fprintf(stderr, "SVC file write/link error - Checkin aborted\n");
  190.     clean();
  191.     exit(1);
  192.   } else
  193.     fprintf(stderr, "Checkin complete.\n");
  194.  
  195.   if (stat(svc, &stb1) < 0 || chmod(svc, stb1.st_mode & 0555) < 0)
  196.     perror("ci: can't chmod SVC file");
  197.  
  198.   if (unlocked) {
  199.     if (stat(file, &stb1) < 0 || chmod(file, stb1.st_mode & 0555) < 0)
  200.         perror("ci: can't chmod source file");
  201.   } else if (relock) {
  202.     if (stat(file, &stb1) < 0 || chmod(file, stb1.st_mode | 0200) < 0)
  203.         perror("ci: can't chmod source file");
  204.   } else
  205.     unlink(file);
  206.  
  207.   clean();
  208.   exit(0);
  209. }
  210.  
  211. rundiff()
  212. {                /* do "diff file original > diffout" */
  213.   int fd;            /* redirected output file */
  214.  
  215.   switch (fork()) {
  216.       case -1:
  217.     perror("ci: fork");    /* error */
  218.     clean();
  219.     exit(1);
  220.  
  221.       case 0:            /* child */
  222.     if ((fd = creat(diffout, 0600)) < 0 || -1 == dup2(fd, 1)) {
  223.         perror("ci: diffout");
  224.         clean();
  225.         exit(1);
  226.     }
  227.     close(fd);
  228.     execlp("diff", "diff", file, original, (char *) 0);
  229.     perror("ci: exec diff failed");
  230.     exit(1);
  231.  
  232.       default:    break;        /* parent */
  233. }
  234.   wait(&status);
  235.   if (0 != status && 1 << 8 != status) {
  236.     fprintf(stderr, "ci: bad return status (0x%x) from diff\n", status);
  237.     clean();
  238.     exit(1);
  239.   }
  240. }
  241.  
  242. logmsg(fp)
  243. FILE *fp;
  244. {
  245.   long now;
  246.  
  247.   time(&now);
  248.   fprintf(stderr, "Enter log message for revision %d (end with ^D or '.'):\n", rev);
  249.   fprintf(fp, "#***SVC*** revision %d %s %s", rev, file, ctime(&now));
  250.   while (NULL != gets(line) && strcmp(line, "."))
  251.     fprintf(fp, "#***SVC*** %s\n", line);
  252. }
  253.  
  254. fname(src, dst)
  255. char *src, *dst;
  256. {
  257.   char *p;
  258.   strcpy(dst, src);
  259.   p = &dst[strlen(src) - strlen(SUFFIX)];
  260.   if (!strcmp(p, SUFFIX)) *p = '\0';
  261. }
  262.  
  263. svcname(src, dst)
  264. char *src, *dst;
  265. {
  266.   char *p;
  267.  
  268.   strcpy(dst, src);
  269.   strcat(dst, SUFFIX);
  270.  
  271.   if (0 != access(dst, 4)) {
  272.     char dirname[PATHLEN];
  273.     if (NULL != (p = strrchr(src, '/')))
  274.         strncpy(dirname, src, p - src + 1);
  275.     else
  276.         dirname[0] = '\0';
  277.     strcat(dirname, SVCDIR);
  278.  
  279.     if (0 == access(dirname, 1)) {
  280.         strcpy(dst, dirname);
  281.         if (NULL == p) {
  282.             strcat(dst, "/");
  283.             strcat(dst, src);
  284.         } else
  285.             strcat(dst, p);
  286.         strcat(dst, SUFFIX);
  287.     }
  288.   }
  289. }
  290.  
  291. lockcheck(fp, rev)
  292. FILE *fp;
  293. int rev;
  294. {
  295.   char lock[40], check[40];
  296.   long pos;
  297.   int ret;
  298.  
  299.   sprintf(lock, "#***SVCLOCK*** %s %d\n", whoami(), rev);
  300.  
  301.   pos = ftell(fp);
  302.   fseek(fp, -((long) strlen(lock)), 2);
  303.   fgets(check, 40, fp);
  304.   ret = (0 == strcmp(lock, check));
  305.   fseek(fp, pos, 0);
  306.  
  307.   return ret;
  308. }
  309.  
  310. void onintr()
  311. {
  312.   fprintf(stderr, "Interrupt - Aborting checkin, cleaning up\n");
  313.   clean();
  314.   exit(1);
  315. }
  316.  
  317. clean()
  318. {
  319.   if (strlen(original))        /* if only more programs made this check! */
  320.     unlink(original);
  321.   if (strlen(diffout)) unlink(diffout);
  322.   if (strlen(newsvc)) unlink(newsvc);
  323. }
  324.  
  325. char *whoami()
  326. {
  327.   struct passwd *pw;
  328.  
  329.   if (NULL != (pw = getpwuid(getuid())))
  330.     return pw->pw_name;
  331.   else
  332.     return "nobody";
  333. }
  334.